#include "stdafx.h"
#include <winsock2.h>
#include "Network.h"

#if defined(WIN32)

void ShowError(int err)
{
	const char *szErr = 0;
	switch(err)
	{
	case WSANOTINITIALISED:szErr = " A successful WSAStartup must occur before using this function. "; break;
	case WSAENETDOWN:szErr = " The network subsystem has failed. "; break;
	case WSAEADDRINUSE:szErr = "  A process on the machine is already bound to the same fully-qualified address and the socket has not been marked to allow address re-use with SO_REUSEADDR. For example, IP address and port are bound in the af_inet case) . (See the SO_REUSEADDR socket option under setsockopt.) "; break;
	case WSAEADDRNOTAVAIL:szErr = " The specified address is not a valid address for this machine "; break;
	case WSAEFAULT:szErr = " The name or the namelen parameter is not a valid part of the user address space, the namelen parameter is too small, the name parameter contains incorrect address format for the associated address family, or the first two bytes of the memory block specified by name does not match the address family associated with the socket descriptor s. "; break;
	case WSAEINPROGRESS:szErr = " A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. "; break;
	case WSAEINVAL:szErr = " The socket is already bound to an address. "; break;
	case WSAENOBUFS:szErr = " Not enough buffers available, too many connections. "; break;
	case WSAENOTSOCK:szErr = " The descriptor is not a socket. "; break;
	default: szErr = "unknown error";
	}

	TRACE1("\n%s\n", szErr);
}

#endif


int IP_InitSocket(STREAMBOX_SOCKET* pSock/*, const char* szLocalIP*/, int nTCPPort/* = 777*/)
{
	int i,err;
	SOCKADDR_IN		addrDecoder;
	int Bind=0;

	if(!pSock)
		return 0;

	*pSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);

	int old_bufsize=0,optlen=sizeof(int);

	if(*pSock == INVALID_SOCKET)
	{
		return 0;
	}

#ifndef WIN32
    (void) fcntl( *pSock, F_SETFD, 1 );
#endif

#ifdef WIN32
	//Fixes Bug in MFC Socket Impl
	LINGER linger = { 1,0 };
	setsockopt(*pSock,SOL_SOCKET,SO_LINGER,(LPCTSTR)&linger,sizeof(linger));
	BOOL bReuse=1;
//	setsockopt(*pSock, SOL_SOCKET, SO_REUSEADDR,(LPCTSTR)&bReuse,sizeof(BOOL));
	// should not use same port as TCP !!!
#endif

	//--------------------------------------------------
	// bind socket 
	::memset(&addrDecoder,0,sizeof(addrDecoder));
	addrDecoder.sin_family = AF_INET;
	addrDecoder.sin_addr.s_addr = INADDR_ANY;//inet_addr(szLocalIP);
	addrDecoder.sin_port=htons(nTCPPort+200);// start with +200
	for (i=0;i<100;i++) 
	{
		if(bind(*pSock, (LPSOCKADDR)&addrDecoder, sizeof(SOCKADDR_IN)) == SOCKET_ERROR){
			addrDecoder.sin_port=htons(ntohs(addrDecoder.sin_port)+1);
		}else{
			Bind=1;
			break;
		}
	}

	if (!Bind){
#if defined(WIN32)
		int err = WSAGetLastError();
		ShowError(err);
#endif
		return 0;
	}



	old_bufsize=64000000;
    err=setsockopt (*pSock, SOL_SOCKET, SO_RCVBUF, (char*)&old_bufsize, optlen);
	old_bufsize=0;
    err=getsockopt (*pSock, SOL_SOCKET, SO_RCVBUF, (char*)&old_bufsize, &optlen);
	return 1;
}

int IP_CloseSocket(STREAMBOX_SOCKET* pSock)
{
	if(!pSock)
		return 0;

#ifdef WIN32
	shutdown(*pSock,SD_BOTH);
	closesocket(*pSock);
#else
	(void) close(*pSock);
#endif
	*pSock=0;
	return 1;

}

int IP_RecievePacket(STREAMBOX_SOCKET *pSock, void *buf, int nBufSize)
{
	int nLen=0;
	int err;
	int timeout = 1;
	int len=sizeof(timeout);
    err=setsockopt(*pSock, SOL_SOCKET, SO_RCVTIMEO,
                           (char* FAR)&timeout, len);
	timeout = 0;
    err=getsockopt(*pSock, SOL_SOCKET, SO_RCVTIMEO,
                           (char* FAR)&timeout, &len);
	//int d=timeGetTime();
	//nLen=recv(Transport_UPD_Socket,(char*)data, 4096,0);

    FD_SET fdread;
    timeval t = { 0, 1 };    // wait up to 10ms
    FD_ZERO( &fdread );
    FD_SET( *pSock, &fdread );

	nLen= select( 0, &fdread, NULL, NULL, &t );

	if( nLen== SOCKET_ERROR){
		 nLen=0;
	}else if( nLen== 0){
		nLen=0;
	}else
		nLen=recv(*pSock,(char*)buf, nBufSize,0);

	/*
	// check if it is audio packet

	BYTE* Data=(BYTE*) data;
	if (nLen && (Data[0]==0xA7)) {
		LastAudioTimeReceived=*(DWORD*)(Data+nLen-4);
	}
	*/
	return nLen;

}

int IP_SetNonDelayMode(STREAMBOX_SOCKET *pSock)
{
	if(!pSock)
		return 0;


	unsigned long  flags = 0, res = 0;
#ifndef WIN32
    flags = fcntl( *pSock, F_GETFL, 0 );
    if ( flags == -1 )
	{
		TRACE1("fcntl F_GETFL -%m\n", flags);
		return 0;
	}
	res = fcntl( *pSock, F_SETFL, flags | O_NDELAY );
    if ( res < 0 )
	{
		TRACE1("fcntl O_NDELAY - %m\n",  res);
		return 0;
	}
#else
	{
		flags = 1;
		res = ioctlsocket(*pSock, FIONBIO, &flags);
		if (res != 0)
		{
			TRACE1("fcntl O_NDELAY - %m\n", res );
			return 0;
		}


		int timeout = 1;
		int len = sizeof(timeout);
		res = setsockopt(*pSock, SOL_SOCKET, SO_RCVTIMEO, (char* FAR)&timeout, len);
		if(res != 0)
		{
			TRACE1("setsockopt - %m\n", res );
			return 0;
		}
	}
#endif


	return 1;
}